package org.example.rzfx.service;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.example.rzfx.config.GlobalConfig;
import org.example.rzfx.dto.AlarmHandleDTO;
import org.example.rzfx.entity.Alarm;
import org.example.rzfx.entity.AlarmRule;
import org.example.rzfx.entity.Log;
import org.example.rzfx.entity.User;
import org.example.rzfx.mapper.AlarmMapper;
import org.example.rzfx.mapper.AlarmRuleMapper;
import org.example.rzfx.mapper.LogMapper;
import org.example.rzfx.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

/**
 * 告警服务
 */
@Service
@Slf4j
public class AlarmService extends ServiceImpl<AlarmMapper, Alarm> {
    
    @Resource
    private AlarmRuleMapper alarmRuleMapper;
    
    @Resource
    private LogMapper logMapper;
    
    @Resource
    private UserMapper userMapper;
    
    @Resource
    private GlobalConfig globalConfig;
    
    @Autowired(required = false)
    private JavaMailSender mailSender;
    
    @Value("${spring.mail.username:}")
    private String mailUsername;
    
    @Resource
    private LogCacheService logCacheService;
    
    /**
     * 检查告警规则并触发
     */
    public void checkAlarmRules() {
        // 查询所有启用的告警规则
        LambdaQueryWrapper<AlarmRule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AlarmRule::getEnabled, 1);
        List<AlarmRule> rules = alarmRuleMapper.selectList(wrapper);
        
        for (AlarmRule rule : rules) {
            try {
                checkSingleRule(rule);
            } catch (Exception e) {
                log.error("检查告警规则失败: " + rule.getRuleName(), e);
            }
        }
    }
    
    /**
     * 检查单个告警规则
     */
    private void checkSingleRule(AlarmRule rule) {
        JSONObject condition = JSON.parseObject(rule.getConditionJson());
        
        // 获取时间窗口（分钟）
        int timeWindow = condition.getIntValue("timeWindow");
        LocalDateTime startTime = LocalDateTime.now().minusMinutes(timeWindow);
        LocalDateTime endTime = LocalDateTime.now();
        
        // ✅ 优先从Redis查询（实时日志）
        long count = countLogsFromRedis(condition, startTime, endTime);
        
        // 如果Redis中没有数据，再查MySQL（历史日志）
        if (count == 0) {
            count = countLogsFromMySQL(condition, startTime, endTime);
        }
        
        int threshold = condition.getIntValue("threshold");
        
        // 判断是否触发告警
        if (count >= threshold) {
            triggerAlarm(rule, (int) count, startTime, endTime);
        }
    }
    
    /**
     * 从Redis统计符合条件的日志数量
     */
    private long countLogsFromRedis(JSONObject condition, LocalDateTime startTime, LocalDateTime endTime) {
        try {
            // 获取时间范围内的所有日期
            List<String> dates = getDatesBetween(startTime, endTime);
            
            long count = 0;
            for (String date : dates) {
                // 获取该日期的所有缓存日志
                List<Log> cachedLogs = logCacheService.getCachedLogs(date);
                
                // 筛选符合条件的日志
                for (Log log : cachedLogs) {
                    if (matchesCondition(log, condition, startTime, endTime)) {
                        count++;
                    }
                }
            }
            
            log.debug("Redis查询结果: 符合条件的日志数={}", count);
            return count;
            
        } catch (Exception e) {
            log.error("从Redis统计日志失败", e);
            return 0;
        }
    }
    
    /**
     * 从MySQL统计符合条件的日志数量（备用方案）
     */
    private long countLogsFromMySQL(JSONObject condition, LocalDateTime startTime, LocalDateTime endTime) {
        try {
            // 构建查询条件
            LambdaQueryWrapper<Log> wrapper = new LambdaQueryWrapper<>();
            wrapper.ge(Log::getTimestamp, startTime).le(Log::getTimestamp, endTime);
            
            // 日志级别
            if (condition.containsKey("logLevel")) {
                wrapper.eq(Log::getLogLevel, condition.getString("logLevel"));
            }
            
            // 系统类型
            if (condition.containsKey("systemType")) {
                wrapper.eq(Log::getSystemType, condition.getString("systemType"));
            }
            
            // 关键字
            if (condition.containsKey("keyword")) {
                wrapper.like(Log::getContent, condition.getString("keyword"));
            }
            
            long count = logMapper.selectCount(wrapper);
            log.debug("MySQL查询结果: 符合条件的日志数={}", count);
            return count;
            
        } catch (Exception e) {
            log.error("从MySQL统计日志失败", e);
            return 0;
        }
    }
    
    /**
     * 判断日志是否符合告警条件
     */
    private boolean matchesCondition(Log logEntity, JSONObject condition, LocalDateTime startTime, LocalDateTime endTime) {
        // 时间范围
        LocalDateTime logTime = logEntity.getTimestamp();
        if (logTime.isBefore(startTime) || logTime.isAfter(endTime)) {
            return false;
        }
        
        // 日志级别
        if (condition.containsKey("logLevel")) {
            String requiredLevel = condition.getString("logLevel");
            if (!requiredLevel.equals(logEntity.getLogLevel())) {
                return false;
            }
        }
        
        // 系统类型
        if (condition.containsKey("systemType")) {
            String requiredSystem = condition.getString("systemType");
            if (!requiredSystem.equals(logEntity.getSystemType())) {
                return false;
            }
        }
        
        // 关键字
        if (condition.containsKey("keyword")) {
            String keyword = condition.getString("keyword");
            if (logEntity.getContent() == null || !logEntity.getContent().contains(keyword)) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 获取时间范围内的所有日期（格式：yyyy-MM-dd）
     */
    private List<String> getDatesBetween(LocalDateTime start, LocalDateTime end) {
        List<String> dates = new ArrayList<>();
        LocalDateTime current = start;
        
        while (!current.toLocalDate().isAfter(end.toLocalDate())) {
            dates.add(current.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            current = current.plusDays(1);
        }
        
        return dates;
    }
    
    /**
     * 触发告警
     */
    private void triggerAlarm(AlarmRule rule, int logCount, LocalDateTime startTime, LocalDateTime endTime) {
        // 创建告警记录
        Alarm alarm = new Alarm();
        alarm.setRuleId(rule.getId());
        alarm.setRuleName(rule.getRuleName());
        alarm.setLogCount(logCount);
        alarm.setAlarmContent(String.format("在%s至%s期间，触发了告警规则【%s】，共%d条日志符合条件",
            startTime, endTime, rule.getRuleName(), logCount));
        alarm.setAlarmTime(LocalDateTime.now());
        alarm.setStatus(0); // 未处理
        
        this.save(alarm);
        
        // 发送邮件通知
        if (rule.getNotifyEmail() != null && !rule.getNotifyEmail().isEmpty()) {
            sendAlarmEmail(rule, alarm);
        }
    }
    
    /**
     * 发送告警邮件
     */
    private void sendAlarmEmail(AlarmRule rule, Alarm alarm) {
        // 检查是否启用邮件通知（全局配置）
        if (!globalConfig.isEmailNotificationEnabled()) {
            log.info("邮件通知功能已禁用，跳过发送邮件");
            return;
        }
        
        if (mailSender == null) {
            log.warn("邮件发送器未配置，跳过邮件发送");
            return;
        }
        
        try {
            SimpleMailMessage message = new SimpleMailMessage();
            // 使用配置文件中的邮箱作为发件人（必须与 spring.mail.username 一致）
            message.setFrom(mailUsername);
            message.setTo(rule.getNotifyEmail().split(","));
            message.setSubject("【日志分析平台】告警通知 - " + rule.getRuleName());
            
            // 邮件内容
            String content = String.format(
                "尊敬的用户，\n\n" +
                "系统检测到告警：\n\n" +
                "告警规则：%s\n" +
                "告警时间：%s\n" +
                "日志数量：%d条\n\n" +
                "详细信息：\n%s\n\n" +
                "请及时登录系统查看和处理。\n\n" +
                "--------------------\n" +
                "日志分析平台自动发送\n" +
                "请勿直接回复此邮件",
                rule.getRuleName(),
                alarm.getAlarmTime(),
                alarm.getLogCount(),
                alarm.getAlarmContent()
            );
            
            message.setText(content);
            
            mailSender.send(message);
            log.info("告警邮件发送成功: {} -> {}", rule.getRuleName(), rule.getNotifyEmail());
        } catch (Exception e) {
            log.error("发送告警邮件失败", e);
        }
    }
    
    /**
     * 处理告警
     */
    public void handleAlarm(AlarmHandleDTO handleDTO) {
        Alarm alarm = this.getById(handleDTO.getAlarmId());
        if (alarm == null) {
            throw new RuntimeException("告警记录不存在");
        }
        
        if (alarm.getStatus() == 1) {
            throw new RuntimeException("告警已被处理");
        }
        
        Long userId = StpUtil.getLoginIdAsLong();
        alarm.setHandlerId(userId);
        alarm.setHandleTime(LocalDateTime.now());
        alarm.setStatus(1);
        alarm.setRemark(handleDTO.getRemark());
        
        this.updateById(alarm);
    }
    
    /**
     * 查询未处理告警
     */
    public List<Alarm> getUnhandledAlarms() {
        LambdaQueryWrapper<Alarm> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Alarm::getStatus, 0).orderByDesc(Alarm::getAlarmTime);
        return this.list(wrapper);
    }
    
    /**
     * 分页查询告警列表（支持筛选）
     */
    public Page<Alarm> listAlarms(Integer pageNum, Integer pageSize, Integer status, String startTime, String endTime) {
        Page<Alarm> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Alarm> wrapper = new LambdaQueryWrapper<>();
        
        // 状态筛选
        if (status != null) {
            wrapper.eq(Alarm::getStatus, status);
        }
        
        // 时间范围筛选
        if (startTime != null && !startTime.isEmpty()) {
            try {
                LocalDateTime start = LocalDateTime.parse(startTime, DateTimeFormatter.ISO_DATE_TIME);
                wrapper.ge(Alarm::getAlarmTime, start);
            } catch (Exception e) {
                log.warn("解析开始时间失败: {}", startTime);
            }
        }
        
        if (endTime != null && !endTime.isEmpty()) {
            try {
                LocalDateTime end = LocalDateTime.parse(endTime, DateTimeFormatter.ISO_DATE_TIME);
                wrapper.le(Alarm::getAlarmTime, end);
            } catch (Exception e) {
                log.warn("解析结束时间失败: {}", endTime);
            }
        }
        
        // 按告警时间倒序
        wrapper.orderByDesc(Alarm::getAlarmTime);
        
        Page<Alarm> result = this.page(page, wrapper);
        
        // 填充处理人姓名
        if (result.getRecords() != null && !result.getRecords().isEmpty()) {
            for (Alarm alarm : result.getRecords()) {
                if (alarm.getHandlerId() != null) {
                    User user = userMapper.selectById(alarm.getHandlerId());
                    if (user != null) {
                        alarm.setHandlerName(user.getUsername());
                    }
                }
            }
        }
        
        return result;
    }
}

